package com.xj.lock;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.LockSupport;

/**
 * Author: baichuan - xiajun
 * Date: 2018/2/3 19:30
 */
public class Louk {
    private volatile int status;
    private Unsafe unsafe = this.unsafe();
    private long offset;
    private Queue<Thread> lockQueue = new ArrayBlockingQueue<Thread>(100);
    private volatile Thread currentLockThread;

    public void lock() {
        if (status <= 0) {
            int cs = status;
            boolean b = unsafe.compareAndSwapInt(this, offset, cs, cs + 1);
            if (!b) {
                lockQueue.add(Thread.currentThread());
                LockSupport.park(this);
            }
            currentLockThread = Thread.currentThread();
        } else {
            if (currentLockThread == Thread.currentThread()) {
                status = status + 1;
            } else {
                lockQueue.add(Thread.currentThread());
                LockSupport.park(this);
                currentLockThread = Thread.currentThread();
            }
        }
    }

    public void unlock() {
        if (Thread.currentThread() != currentLockThread) {
            throw new RuntimeException("非当前线程在运行");
        }
        status = status - 1;
        if (status <= 0) {
            currentLockThread = null;
            Thread t = lockQueue.poll();
            if (t != null) {
                LockSupport.unpark(t);
            }
        }
    }

    private Unsafe unsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);
            Field valueField = Louk.class.getDeclaredField("status");
            offset = unsafe.objectFieldOffset(valueField);
            return unsafe;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws InterruptedException {
        Louk louk = new Louk();
        louk.lock();
        System.out.println("lock 1");
        louk.lock();
        System.out.println("lock 2");
        new Thread(() -> {
            System.out.println("thread2 get lock ...");
            louk.lock();
            System.out.println("thread2 get lock sucess");
        }).start();
        louk.unlock();
        louk.unlock();
        Thread.sleep(10000);

    }
}
